﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

using System.Windows.Forms;
using SlimDX;
using SlimDX.Windows;
using D3D10 = SlimDX.Direct3D10;
using DXGI = SlimDX.DXGI;

using SCS.Objects;

namespace SCS.GFX
{
    static class Renderer
    {
        static XFile XM;
        
        static D3D10.Viewport           ViewArea;
        static DXGI.SwapChain           SwapChain;
        static public D3D10.Device      Device;
        static D3D10.RenderTargetView   RenderTarget;
        static D3D10.Texture2D          DepthStencil;
        static D3D10.DepthStencilView   DepthStencilView;

        static public Matrix    View;
        static public Matrix    Projection;
        static public Camera    Camera;
        static public RefGrid   Grid;

        static public void Shutdown()
        {
            Device.ClearState();
            RenderTarget.Dispose();
            Device.Dispose();
            SwapChain.Dispose();
            Logger.WriteLog("Graphics subsystem shut down");
        }
        
        static public void Render(RenderInfo FrameInfo)
        {
            Device.ClearRenderTargetView(RenderTarget, Color.Black);
            Device.ClearDepthStencilView(DepthStencilView, D3D10.DepthStencilClearFlags.Depth, 1.0f, 0);


            Grid.Render(FrameInfo);

            foreach (Entity e in Game.Entities)
            {
                e.Render(FrameInfo);
            }

            XM.Render(FrameInfo);

            SwapChain.Present(0, DXGI.PresentFlags.None);
        }

        static public void Initialise(Form RenderForm)
        {
            Logger.WriteLog("Initialising Graphics Subsystem...");
            DXGI.SwapChainDescription swapChainDescription = new SlimDX.DXGI.SwapChainDescription();
            DXGI.ModeDescription modeDescription = new DXGI.ModeDescription();
            DXGI.SampleDescription sampleDescription = new DXGI.SampleDescription();

            modeDescription.Format = DXGI.Format.R8G8B8A8_UNorm;
            modeDescription.RefreshRate = new Rational(60, 1);
            modeDescription.Scaling = DXGI.DisplayModeScaling.Unspecified;
            modeDescription.ScanlineOrdering = DXGI.DisplayModeScanlineOrdering.Unspecified;
            modeDescription.Width = RenderForm.ClientRectangle.Width;
            modeDescription.Height = RenderForm.ClientRectangle.Height;

            sampleDescription.Count = 1;
            sampleDescription.Quality = 0;

            swapChainDescription.ModeDescription = modeDescription;
            swapChainDescription.SampleDescription = sampleDescription;
            swapChainDescription.BufferCount = 1;
            swapChainDescription.Flags = DXGI.SwapChainFlags.None;
            swapChainDescription.IsWindowed = true;
            swapChainDescription.OutputHandle = RenderForm.Handle;
            swapChainDescription.SwapEffect = DXGI.SwapEffect.Discard;
            swapChainDescription.Usage = DXGI.Usage.RenderTargetOutput;

            D3D10.Device.CreateWithSwapChain(null, D3D10.DriverType.Hardware, D3D10.DeviceCreationFlags.Debug, swapChainDescription, out Device, out SwapChain);

            D3D10.Texture2DDescription desc = new D3D10.Texture2DDescription();
            desc.Width = RenderForm.ClientRectangle.Width;
            desc.Height = RenderForm.ClientRectangle.Height;
            desc.MipLevels = 1;
            desc.ArraySize = 1;
            desc.Format = SlimDX.DXGI.Format.D32_Float;
            desc.SampleDescription = sampleDescription;
            desc.Usage = D3D10.ResourceUsage.Default;
            desc.BindFlags = D3D10.BindFlags.DepthStencil;
            desc.CpuAccessFlags = D3D10.CpuAccessFlags.None;
            desc.OptionFlags = D3D10.ResourceOptionFlags.None;

            D3D10.DepthStencilViewDescription dsvd = new D3D10.DepthStencilViewDescription();
            dsvd.Format = desc.Format;
            if (desc.SampleDescription.Count > 1)
                dsvd.Dimension = D3D10.DepthStencilViewDimension.Texture2DMultisampled;
            else
                dsvd.Dimension = D3D10.DepthStencilViewDimension.Texture2D;
            DepthStencil = new D3D10.Texture2D(Device, desc);
            DepthStencilView = new D3D10.DepthStencilView(Device, DepthStencil, dsvd);
            
            /*



                RasterizerStateDescription rsDesc = new RasterizerStateDescription();
                rsDesc.FillMode = SlimDX.Direct3D10.FillMode.Solid;
                rsDesc.CullMode = CullMode.Back;
                rsDesc.IsDepthClipEnabled = true;
                if (desc.SampleDescription.Count > 1)
                    rsDesc.IsMultisampleEnabled = true;
                else
                    rsDesc.IsMultisampleEnabled = false;

                Direct3D10.RasterizerState = RasterizerState.FromDescription(Direct3D10.Device, rsDesc);
                Direct3D10.Device.Rasterizer.State = Direct3D10.RasterizerState;
            }

            Direct3D10.Device.OutputMerger.SetTargets(Direct3D10.DepthStencilView, Direct3D10.RenderTarget);
* 
             */


            using (D3D10.Texture2D resource = D3D10.Texture2D.FromSwapChain<D3D10.Texture2D>(SwapChain, 0))
            {
                RenderTarget = new D3D10.RenderTargetView(Device, resource);
            }

            ViewArea = new D3D10.Viewport();
            ViewArea.X = 0;
            ViewArea.Y = 0;
            ViewArea.Width = RenderForm.ClientRectangle.Width;
            ViewArea.Height = RenderForm.ClientRectangle.Height;
            ViewArea.MinZ = 0.0f;
            ViewArea.MaxZ = 1.0f;

            //Create a simple projection matrix, 45° fov angle, aspect = width/height, and a 0.1 near and 100.0 far plane
            Projection = Matrix.PerspectiveFovLH(CustomMath.DegreeToRadian(45), ViewArea.Width / ViewArea.Height, 0.1f, 100.0f);
            //Create a simple view matrix, camera stands at -10 units Z-depth from the origin, and looks at the origin. The up-vector is the Y-axis

            Device.Rasterizer.SetViewports(ViewArea);
            Device.OutputMerger.SetTargets(DepthStencilView, RenderTarget);
            //Device.OutputMerger.SetTargets(RenderTarget);
            Logger.WriteLog("...Done!");

            Grid = new RefGrid();
            Camera = new Camera();
            Camera.UpdateView();

            XM = new XFile("e:\\f.x");


            //Test = new ColladaMeshObject("tube", new Vector3(1.0f, 1.0f, 1.0f));

        }

    }
}